package com.weixing.mall.pay.channel.wx;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.weixing.mall.base.constant.DatePattern;
import com.weixing.mall.base.exception.BusinessException;
import com.weixing.mall.pay.INotify;
import com.weixing.mall.pay.NotifyResult;
import com.weixing.mall.pay.channel.wx.sdk.WXPayConstants;
import com.weixing.mall.pay.channel.wx.sdk.WXPayUtil;
import com.weixing.mall.pay.properties.WxPayProperties;
import com.weixing.mall.pay.util.XmlUtil;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @ClassName WxNotify
 * @Description
 * @Author Small
 * @Date 2019/12/10 16:47
 * @Version 1.0
 **/
@Slf4j
public class WxNotify implements INotify {
    protected static final String SUCCESS = "SUCCESS";
    private WxPayProperties payProperties;
    private List<Map<String, Object>> setVoMapList;

    public WxNotify(WxPayProperties payProperties) {
        this.payProperties = payProperties;
    }

    public WxNotify(List<Map<String, Object>> setVoMapList) {
        this.setVoMapList = setVoMapList;
    }

    /**
     * 方法描述: 支付回调
     * @Author Small
     * @param request
     * @Date 2019/12/4 14:58
     * @return com.weixing.mall.pay.NotifyResult
     */
    @Override
    public NotifyResult doNotify(HttpServletRequest request) {
        try {
            String xmlStr = getStrFromInputSteam(request.getInputStream());
            Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
            // 动态查找这次回调该匹配哪一个配置
            String out_trade_no = map.get("out_trade_no");
            Date now = DateUtil.parse(out_trade_no.substring(0, 14), DatePattern.PURE_DATETIME_PATTERN);
            int size = setVoMapList.size();
            Map<String, Object> paySetMap = null;
            for (int i = 0; i < size; i++) {
                Map<String, Object> stringObjectMap = setVoMapList.get(i);
                Date effectStartTime = (Date) stringObjectMap.get("effectStartTime");
                Date effectEndTime = (Date) stringObjectMap.get("effectEndTime");
                if (now.compareTo(effectStartTime) >= 0 && now.compareTo(effectEndTime) <= 0) {
                    paySetMap = stringObjectMap;
                    break;
                }
            }
            if (null == paySetMap){
                throw  new BusinessException("支付回调失败，失败原因：找不到相应的支付配置");
            }
            String paramSet = (String) paySetMap.get("paramSet");
            JSONObject jsonObject = JSON.parseObject(paramSet);
            // 验签
            boolean signatureValid = WXPayUtil.isSignatureValid(map, jsonObject.getString("key"), WXPayConstants.SignType.HMACSHA256);
            if (signatureValid) {
                WxNotifyResp callResponse = (WxNotifyResp) XmlUtil.xmlStr2Bean(xmlStr, "xml", WxNotifyResp.class);
                if (SUCCESS.equals(callResponse.getReturnCode())) {
                    if (SUCCESS.equals(callResponse.getResultCode())) {
                        return NotifyResult.tradeSuccess(callResponse);
                    } else {
                        return NotifyResult.tradeNotSuccess(callResponse.getErrCode(), callResponse.getErrCodeDes());
                    }
                } else {
                    // 通信失败
                    return NotifyResult.fail(callResponse.getReturnCode(), callResponse.getReturnMsg());
                }

            } else {
                NotifyResult.invalidSign();
            }
            // 解析微信回调参数
        } catch (Exception e) {
            log.warn("WxNotify=> 回调时发生异常", e);
        }
        return NotifyResult.unknowException();
    }

    @Override
    public String success() {
        return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
    }

    @Override
    public String fail() {
        return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
    }

    private String getStrFromInputSteam(InputStream in) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(in, "UTF-8"));
        //最好在将字节流转换为字符流的时候 进行转码
        StringBuffer buffer = new StringBuffer();
        String line = "";
        while ((line = bf.readLine()) != null) {
            buffer.append(line);
        }

        return buffer.toString();
    }
}
